package com.elitel.frame.base.service.impl;

import com.elitel.frame.base.component.RedisCacheComponent;
import com.elitel.frame.base.component.exportprojectdata.DataBaseConnInfo;
import com.elitel.frame.base.service.CfgFieldService;
import com.elitel.frame.base.service.CfgTableService;
import com.elitel.frame.core.service.impl.BaseServiceImpl;
import com.elitel.frame.main.dao.CfgTableMapper;
import com.elitel.frame.main.dao.ext.*;
import com.elitel.frame.main.entity.*;
import com.elitel.frame.main.entity.vo.KeyValueModelVo;
import com.elitel.frame.main.entity.vo.PageResponseVo;
import com.elitel.frame.main.entity.vo.ZTreeDataModelVo;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class CfgTableServiceImpl extends BaseServiceImpl
        implements CfgTableService {
    private static final Logger logger = LoggerFactory.getLogger(CfgTableServiceImpl.class);
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Autowired
    private ExtCfgDbMapper extCfgDbMapper;
    @Autowired
    private ExtCfgTableMapper extCfgTableMapper;
    @Autowired
    private CfgTableMapper cfgTableMapper;
    @Autowired
    private ExtCfgFieldMapper extCfgFieldMapper;
    @Autowired
    private ExtBaseFieldconfigMapper extBaseFieldconfigMapper;
    @Autowired
    private ExtBaseFieldaddonsMapper extBaseFieldaddonsMapper;
    @Autowired
    private RedisCacheComponent redisCacheComponent;
    @Autowired
    private ExtCfgExtendMapper extCfgExtendMapper;
    @Autowired
    private ExtCfgExtmasterMapper extCfgExtmasterMapper;
    @Autowired
    private ExtBaseFieldenumMapper extBaseFieldenumMapper;
    @Autowired
    private ExtCfgEditMapper extCfgEditMapper;
    @Autowired
    private DataBaseConnInfo dataBaseConnInfo;
    @Autowired
    private CfgFieldService cfgFieldService;

    @Override
    public List<ZTreeDataModelVo> getAllList() {
        List<ZTreeDataModelVo> ztreeList = new ArrayList<ZTreeDataModelVo>();
        List<CfgDb> cfgdbList = extCfgDbMapper.getAllListCfgDb();
        if (cfgdbList != null && !cfgdbList.isEmpty()) {
            for (CfgDb cb : cfgdbList) {
                ZTreeDataModelVo ztmodelDataModelVo = new ZTreeDataModelVo();
                ztmodelDataModelVo.setId(cb.getDbKey());
                ztmodelDataModelVo.setName(cb.getDbMark() + "(" + cb.getDbName() + ")");
                ztmodelDataModelVo.setHint("数据库版本:" + cb.getDbVersion() + ",数据库名称:" + cb.getDbName());
                ztmodelDataModelVo.setIsMark("1");
                List<CfgTable> cfgTablesList = extCfgTableMapper.getListBydbkeyAndType(cb.getDbKey(), 1);
                if (cfgTablesList != null && !cfgTablesList.isEmpty()) {
                    List<ZTreeDataModelVo> ztreeTable = new ArrayList<ZTreeDataModelVo>();
                    for (CfgTable cfgt : cfgTablesList) {
                        ZTreeDataModelVo zttable = new ZTreeDataModelVo();
                        zttable.setId(cfgt.getDtConfigId());
                        zttable.setName(cfgt.getDtNameCn() + "(" + cfgt.getDtName() + ")");
                        zttable.setHint("数据库:" + cb.getDbName() + ",表:" + cfgt.getDtName());
                        zttable.setIsMark("2");
                        ztreeTable.add(zttable);
                    }
                    ztmodelDataModelVo.setChildren(ztreeTable);
                }

                ztreeList.add(ztmodelDataModelVo);
            }
        }
        return ztreeList;
    }

    @Override
    public List<ZTreeDataModelVo> getViewList() {
        List<ZTreeDataModelVo> ztreeList = new ArrayList<ZTreeDataModelVo>();
        List<CfgDb> cfgdbList = extCfgDbMapper.getAllListCfgDb();
        if (cfgdbList != null && !cfgdbList.isEmpty()) {
            for (CfgDb cb : cfgdbList) {
                ZTreeDataModelVo ztmodelDataModelVo = new ZTreeDataModelVo();
                ztmodelDataModelVo.setId(cb.getDbKey());
                ztmodelDataModelVo.setName(cb.getDbMark() + "(" + cb.getDbName() + ")");
                ztmodelDataModelVo.setHint("数据库版本:" + cb.getDbVersion() + ",数据库名称:" + cb.getDbName());
                ztmodelDataModelVo.setIsMark("1");
                List<CfgTable> cfgTablesList = extCfgTableMapper.getListBydbkeyAndType(cb.getDbKey(), 2);
                if (cfgTablesList != null && !cfgTablesList.isEmpty()) {
                    List<ZTreeDataModelVo> ztreeTable = new ArrayList<ZTreeDataModelVo>();
                    for (CfgTable cfgt : cfgTablesList) {
                        ZTreeDataModelVo zttable = new ZTreeDataModelVo();
                        zttable.setId(cfgt.getDtConfigId());
                        zttable.setName(cfgt.getDtNameCn() + "(" + cfgt.getDtName() + ")");
                        zttable.setHint("数据库:" + cb.getDbName() + ",视图:" + cfgt.getDtName());
                        zttable.setIsMark("2");
                        ztreeTable.add(zttable);
                    }
                    ztmodelDataModelVo.setChildren(ztreeTable);
                }

                ztreeList.add(ztmodelDataModelVo);
            }
        }
        return ztreeList;
    }

    @Override
    public CfgTable queryCfgTable(String dtConfigId) {
        return extCfgTableMapper.queryCfgTable(dtConfigId);
    }

    @Override
    public String getdtConfigIdIs(String dtconfigId) {
        return extCfgTableMapper.getdtConfigIdNum(dtconfigId);
    }

    @Override
    @Transactional
    public int addcfgTable(CfgTable cfgTable) {
        int insertSelective = cfgTableMapper.insertSelective(cfgTable);
        redisCacheComponent.freshCfgTableRedisCache(cfgTable.getDtConn());
        return insertSelective;
    }

    @Override
    @Transactional
    public int updatecfgTable(CfgTable cfgTable) {
        int updateByPrimaryKeySelective = cfgTableMapper.updateByPrimaryKeySelective(cfgTable);
        redisCacheComponent.freshCfgTableRedisCache(cfgTable.getDtConn());
        return updateByPrimaryKeySelective;
    }

    @Override
    public CfgTable getInfoByDtconfigId(String dtConfigId) {
        return extCfgTableMapper.getInfoByDtconfigId(dtConfigId);
    }

    @Override
    public CfgTable getTableBydtConfigIdAndTableType(String dtConfigId, Integer tableType) {
        return extCfgTableMapper.getTableBydtConfigIdAndtableType(dtConfigId, tableType);
    }

    @Override
    public List<ZTreeDataModelVo> getDabaBaseList() {
        List<ZTreeDataModelVo> ztreeList = new ArrayList<ZTreeDataModelVo>();
        List<CfgDb> cfgdbList = extCfgDbMapper.getAllListCfgDb();
        if (cfgdbList != null && !cfgdbList.isEmpty()) {
            for (CfgDb cb : cfgdbList) {
                ZTreeDataModelVo ztmodelDataModelVo = new ZTreeDataModelVo();
                ztmodelDataModelVo.setId(cb.getDbKey());
                ztmodelDataModelVo.setName(cb.getDbMark() + "(" + cb.getDbName() + ")");
                ztmodelDataModelVo.setHint("数据库版本:" + cb.getDbVersion() + ",数据库名称:" + cb.getDbName());
                ztmodelDataModelVo.setIsMark("1");
                ztmodelDataModelVo.setIcon("/theme/zTree/zTreeStyle/img/diy/database.png");
                ztreeList.add(ztmodelDataModelVo);
            }
        }


        return ztreeList;
    }

    @Override
    public List<CfgTable> getListbyConn(String key) {
        return extCfgTableMapper.getListBydbkey(key);
    }

    @Override
    public List<CfgTable> getListByConnAndtableType(String dbkey, Integer tableType) {
        return extCfgTableMapper.getListBydbkeyAndType(dbkey, tableType);
    }

    @Override
    @Transactional
    public int deleteTableInfo(String dtConfigId) {
        CfgTable cfgTable = extCfgTableMapper.queryCfgTable(dtConfigId);
        int Result = 0;
        boolean isdel = true;

        //查询单表服务是否使用
        List<CfgExtend> cfgExtends = extCfgExtendMapper.cfgExtendBydtconfigId(dtConfigId);
        if (cfgExtends != null && cfgExtends.size() > 0) {
            isdel = false;
        }
        //查询主从表服务是否使用
        List<CfgExtmaster> cfgExtmasters = extCfgExtmasterMapper.getExtMasterBydtConfigId(dtConfigId);
        if (cfgExtends != null && cfgExtends.size() > 0) {
            isdel = false;
        }
        //查询单表编辑服务是否使用
        List<CfgEdit> cfgEdits = extCfgEditMapper.selectCfgEditBydtconfigId(dtConfigId);
        if (cfgEdits != null && cfgEdits.size() > 0) {
            isdel = false;
        }

        //删除元数据基本信息表
        if (isdel) {
            Result += extBaseFieldaddonsMapper.deleteBaseFieldaddonsBydtconfig(dtConfigId);//删除基本信息附件属性
            Result += extBaseFieldconfigMapper.deleteFieldConfigbydtconfig(dtConfigId);//删除字段关联表
            Result += extCfgFieldMapper.deleteFieldBydtconfigid(dtConfigId);//删除字段信息表
            Result += extCfgTableMapper.deleteTableBydtConfigId(dtConfigId);//删除表信息
            Result += extBaseFieldenumMapper.deleteFieldenumBydtConfigId(dtConfigId);//删除表枚举字段信息

            redisCacheComponent.freshCfgTableRedisCache(cfgTable.getDtConn());
            redisCacheComponent.freshCfgFieldRedisCache(dtConfigId);

//            redisCacheService.delObject("CFG_FIELD_" + dtConfigId, RedisDbIndex.value);
            redisCacheComponent.delCfgFieldRedisCache(dtConfigId);
        }

        return Result;
    }

    @Override
    public List<CfgTable> selectTableMap(String dbid) {
        return cfgTableMapper.selectTableMap(dbid);
    }

    @Override
    public String selectTableName(String dbid) {
        return cfgTableMapper.selectTableNames(dbid);
    }

    @Override
    public CfgTable getDataViewBydtconfigId(String dtConfigId) {
        return extCfgTableMapper.getDataViewBydtconfigId(dtConfigId);
    }

    /**
     * show 通过dbkey分页查询配置的数据表信息
     * create by guoyanfei on 2018/12/25
     * 实现方法
     *
     * @param dbkey     数据库主键
     * @param paramtxt  参数条件
     * @param pageNo    当前页
     * @param pageSize  页大小
     * @param tableType 表类型(1数据表,2数据视图)
     * @return 数据集合
     */
    @Override
    @Transactional
    public PageResponseVo getCfgTablebyPage(String dbkey, String paramtxt, Integer pageNo, Integer pageSize, Integer tableType) {
        PageResponseVo pageResponseVo = new PageResponseVo();
        List<CfgTable> cfgTableList = new ArrayList<>();
        String databaseType = dataBaseConnInfo.dataBaseType;
        Integer beginRow = (pageNo - 1) * pageSize;
        Integer endRow = pageNo * pageSize;
        switch (databaseType) {
            case "oracle":
            case DataSourceType.DM:
                cfgTableList = extCfgTableMapper.getListbyPageinoracle((beginRow + 1), endRow,
                        dbkey, paramtxt, tableType);
                break;
            case "mysql":
            case "h2":
                cfgTableList = extCfgTableMapper.getListbyPageinmysql(beginRow, pageSize,
                        dbkey, paramtxt, tableType);
                break;
            case "sqlite":
                cfgTableList = extCfgTableMapper.getListbyPageinSqlite(beginRow, pageSize,
                        dbkey, paramtxt, tableType);
                break;
            case DataSourceType.POSTGRES:
                cfgTableList = extCfgTableMapper.getListbyPageinPG(beginRow, pageSize,
                        dbkey, paramtxt, tableType);
                break;
        }
        Integer count = 0;
        if (databaseType.equals("sqlite")) {
            count = extCfgTableMapper.getCountBydbkeySqlite(dbkey, paramtxt, tableType);
        } else {
            count = extCfgTableMapper.getCountBydbkey(dbkey, paramtxt, tableType);
        }
        pageResponseVo.setRows(cfgTableList);
        pageResponseVo.setTotal(count);
        return pageResponseVo;
    }

    @Override
    public PageResponseVo getCfgTableTreebyPage(String id, String paramtxt, Integer pageNo, Integer pageSize, String contentType) {
        PageResponseVo pageResponseVo = new PageResponseVo();
        List<CfgTable> cfgTableList = new ArrayList<>();
        Integer beginRow = (pageNo - 1) * pageSize;
        Integer endRow = pageNo * pageSize;
        Integer count = 0;
        //其他类
        if (id.startsWith("99_")) {
            String dt_conn = id.substring(3);
            if (DataSourceType.POSTGRES.equals(dataBaseConnInfo.dataBaseType)) {
                cfgTableList = extCfgTableMapper.getListByPageTreeOthersPG(beginRow, pageSize,
                        dt_conn, paramtxt);
            } else {
                cfgTableList = extCfgTableMapper.getListByPageTreeOthers(beginRow, pageSize,
                        dt_conn, paramtxt);
            }
            count = extCfgTableMapper.getCountBydbkeyTreeOthers(dt_conn, paramtxt);
        } else {
            if (DataSourceType.POSTGRES.equals(dataBaseConnInfo.dataBaseType)) {
                cfgTableList = extCfgTableMapper.getListbyPageTreeinPG(beginRow, pageSize,
                        id, paramtxt, Integer.valueOf(contentType));
            } else {
                cfgTableList = extCfgTableMapper.getListbyPageTreeinmysql(beginRow, pageSize,
                        id, paramtxt, Integer.valueOf(contentType));
            }
            count = extCfgTableMapper.getCountBydbkeyTree(id, paramtxt, Integer.valueOf(contentType));
        }

        //获取表数据分类Map
        List<Map<String, String>> tableTypeMapList = extCfgTableMapper.getTableTypeMap();
        Map<String, String> tableTypeMap = tableTypeMapList.stream().collect(Collectors.toMap(e -> e.get("typeid"), e -> e.get("typename")));

        for (CfgTable cfgTable : cfgTableList) {
            String tableCategory = cfgTable.getTypeId();
            if (tableCategory == null || tableTypeMap.get(tableCategory) == null) {
                cfgTable.setModuleMark("其它");
            } else {
                cfgTable.setModuleMark(tableTypeMap.get(tableCategory));
            }
        }

        pageResponseVo.setRows(cfgTableList);
        pageResponseVo.setTotal(count);
        return pageResponseVo;
    }

    @Override
    public Integer getRecourdTotalBydbkey(String id, String paramtxt, String contentType) {
        Integer recourdTotal = 0;
        if (id.startsWith("99_")) {
            String dt_conn = id.substring(3);
            recourdTotal = extCfgTableMapper.getRecourdTotalBydbkeyOthers(dt_conn, paramtxt);
        } else {
            recourdTotal = extCfgTableMapper.getRecourdTotalBydbkey(id, paramtxt, Integer.valueOf(contentType));
        }
        return recourdTotal;
    }

    @Override
    public List<Map<String, String>> getJStreeParams(int mark) {
        if (DataSourceType.POSTGRES.equals(dataBaseConnInfo.dataBaseType)) {
            return extCfgTableMapper.getJStreeParamsPG(mark);
        }
        return extCfgTableMapper.getJStreeParams(mark);
    }

    @Override
    public Integer updateCfgtableCount(Integer dataquantity, String dt_name, String dbnm) {
        return extCfgTableMapper.updateCfgtableCount(dataquantity, dt_name, dbnm);
    }

    @Override
    public Integer refreshCfgtableCount() {
        return extCfgTableMapper.refreshCfgtableCount();
    }

    @Override
    public Integer refreshCenterinfo(Integer id, Double dataquantity) {
        return extCfgTableMapper.refreshCenterinfo(id, dataquantity);
    }

    @Override
    public CfgTable getInfoByGuid(String guid) {
        return extCfgTableMapper.getInfoByGuid(guid);
    }

    @Override
    public Map<String, String> getInfoByModuleDtName(int module, String dbName, String dtName) {
        return extCfgTableMapper.getInfoByModuleDtName(module, dbName, dtName);
    }

    @Override
    public void loadTableInfo(CfgDb cfgDb, List<Map<String, String>> maplist, String moduleMark, Map<String, String> pkNameMap, Map<String, List<KeyValueModelVo>> allFieldMap) {
        if (pkNameMap == null || allFieldMap == null) {
            return;
        }
        Map<String, String> dtConfigIdsMap = new HashMap<String, String>();
        String dbkey = cfgDb.getDbKey();
        List<CfgTable> allCfgTable = getAllCfgTable();
        List<String> allDtConfigIdList = allCfgTable.stream().map(CfgTable::getDtConfigId).collect(Collectors.toList());
        List<Map<String, String>> tableMapperInfoMapList = extCfgTableMapper.getInfoMapListByModule(1);

        Map<String, Map<String, String>> tableInfoMap = tableMapperInfoMapList.stream()
                .collect(Collectors.toMap(
                        map -> (map.get("dbname") + "," + map.get("dt_name")).toLowerCase(),   // keyMapper，提取id属性作为新Map的键
                        map -> map,             // valueMapper，直接将整个Map作为值
                        (existing, replacement) -> existing  // 合并函数，如果有重复的键，保留旧值
                ));

        // 遍历集合,取出各个表的信息
        List<CfgTable> cfgTableList = new ArrayList<>();
        for (Map<String, String> map : maplist) {
            String dtname = map.get("table_name");
            if (StringUtils.isBlank(dtname)) {
                continue;
            }
            String dtConfigId = dbkey + "_" + dtname;
            if (!allDtConfigIdList.contains(dtConfigId)) {
                dtConfigIdsMap.put(dtConfigId, dtname);
                // 获取该表主键primarykey
                String primaryName = pkNameMap.get(dtname);
                String dtOrder = primaryName;
                //若主键不存在，则取第一个字段作为排序字段
                if (StringUtils.isBlank(primaryName)) {
                    List<KeyValueModelVo> listFields = allFieldMap.get(dtname);
                    if (listFields != null && !listFields.isEmpty()) {
                        KeyValueModelVo keyValueModelVo = listFields.get(0);
                        dtOrder = keyValueModelVo.getKey();
                    }
                }

                // 表属性赋值
                String dtNameCn = map.get("comments");
                String table_count = String.valueOf(map.get("table_count"));
                CfgTable cfgTable = new CfgTable();
                cfgTable.setDtName(dtname);
                cfgTable.setDtConfigId(dtConfigId);
                cfgTable.setDtNameCn(dtNameCn);
                cfgTable.setDtOrder(dtOrder);
                cfgTable.setDtConn(dbkey);
                cfgTable.setDtPrimarykey(primaryName);
                cfgTable.setDtRemark(dtNameCn);
                cfgTable.setGuid(UUID.randomUUID().toString());
                cfgTable.setCreatedate(dateFormat.format(new Date()));
                cfgTable.setDtTabletype(1);
                cfgTable.setDbName(cfgDb.getDbName());
                cfgTable.setModuleMark(moduleMark);
                cfgTable.setDataQuantity(StringUtils.isNumeric(table_count) ? Integer.parseInt(table_count) : 0);

                Map<String, String> infoMap = tableInfoMap.get(String.format("%s,%s", cfgDb.getDbName(), dtname).toLowerCase());
                if (infoMap != null) {
                    cfgTable.setTypeId(infoMap.get("typeid"));
                    String dt_cnname = infoMap.get("dt_cnname");
                    if (StringUtils.isNotBlank(dt_cnname)) {
                        cfgTable.setDtNameCn(dt_cnname);
                    }
                }

                cfgTableList.add(cfgTable);
                if (cfgTableList.size() % 100 == 0) {
                    batchInsertCfgTable(cfgTableList);
                    cfgTableList = new ArrayList<>();
                }
            }
        }
        batchInsertCfgTable(cfgTableList);

        List<CfgField> cfgFieldList = new ArrayList<>();
        for (String dtConfigId : dtConfigIdsMap.keySet()) {
            String dtname = dtConfigIdsMap.get(dtConfigId);
            List<KeyValueModelVo> keyValueModelVos = allFieldMap.get(dtname);
            String primaryNameStr = pkNameMap.get(dtname);
            List<String> pkList = primaryNameStr != null ? Arrays.asList(primaryNameStr.split(",")) : new ArrayList<>();
            for (int i = 0; i < keyValueModelVos.size(); i++) {
                KeyValueModelVo keyValueModelVo = keyValueModelVos.get(i);
                String dfName = keyValueModelVo.getKey();
                String dfNameCN = keyValueModelVo.getValue();
                String dataType = keyValueModelVo.getDataType();

                CfgField cfgField = new CfgField();
                cfgField.setGuid(UUID.randomUUID().toString());
                cfgField.setDtConfigId(dtConfigId);
                cfgField.setDtName(dtname);
                cfgField.setDfName(dfName);
                cfgField.setDfNameCn(StringUtils.isNotBlank(dfNameCN) ? dfNameCN : dfName);
                cfgField.setDtType(dataType);
                cfgField.setDfOrder(i + 1);
                cfgField.setDfIsprimarykey(pkList.contains(dfName) ? 1 : 0);
                cfgField.setCreatedate(dateFormat.format(new Date()));

                cfgFieldList.add(cfgField);
                if (cfgFieldList.size() % 100 == 0) {
                    cfgFieldService.batchInsertCfgField(cfgFieldList);
                    cfgFieldList = new ArrayList<>();
                }
            }
        }

        cfgFieldService.batchInsertCfgField(cfgFieldList);
    }

    @Override
    public void batchInsertCfgTable(List<CfgTable> cfgTableList) {
        if (cfgTableList == null || cfgTableList.isEmpty()) {
            return;
        }
        cfgTableMapper.batchInsertCfgTable(cfgTableList);
    }

    @Override
    public List<CfgTable> getAllCfgTable() {
        return cfgTableMapper.selectAllTable();
    }

    @Override
    public void refreshTableCount(String dbKey, List<Map<String, Object>> dbTableRecordCountList) {
        if (dbTableRecordCountList == null || dbTableRecordCountList.isEmpty()) {
            return;
        }

        //获取该数据源配置的表列表
        List<CfgTable> cfgTableList = getListbyConn(dbKey);
        dbTableRecordCountList = dbTableRecordCountList.stream()
                .filter(table -> cfgTableList.stream()
                        .anyMatch(o -> o.getDtName().equals(table.get("table_name"))))
                .collect(Collectors.toList());

        int successCount = 0;
        List<String> failTables = new ArrayList<>();
        for (Map<String, Object> resultMap : dbTableRecordCountList) {
            String tableName = String.valueOf(resultMap.get("table_name"));
            Object tableCount = resultMap.get("table_count");
            int count = tableCount != null ? BigDecimal.valueOf(Double.parseDouble(String.valueOf(tableCount))).intValue() : 0;

            int executeUpdate = updateCfgtableCount(count, tableName, dbKey);
            if (executeUpdate > 0) {
                successCount++;
            } else {
                failTables.add(tableName);
            }
        }
        logger.info("更新数据表总数：" + dbTableRecordCountList.size());
        logger.info("更新成功总数：" + successCount);

        if (successCount != dbTableRecordCountList.size()) {
            logger.info("更新失败总数：" + (dbTableRecordCountList.size() - successCount));
            logger.info("更新失败的表为：" + String.join(",", failTables));
        }
    }

    @Override
    public int getCount() {
        Integer count = cfgTableMapper.getCount();
        if (count == null) {
            return 0;
        }
        return count;
    }

    @Override
    public long getRecordCount() {
        Long recordCount = cfgTableMapper.getRecordCount();
        if (recordCount == null) {
            return 0;
        }
        return recordCount;
    }


}
